﻿using iTool.Common.Models;
using iTool.Common.Responses;
using iTool.Utils;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;

namespace iTool.Cloud.NetCore
{


    public abstract class AbstractiToolCommand : AbstractiToolConnection
    {

        public Task<string> invokeMethodAsync(string fn, params object[] args)
        {
            TaskCompletionSource<string> completionSource = new TaskCompletionSource<string>();

            var taskBody = _invokeMethod(completionSource, fn, args);

            this.Tasks.Enqueue(taskBody);

            return completionSource.Task;
        }
        public Promise invokeMethod(string fn, params object[] args)
        {
            var promise = new Promise();

            var taskBody = _invokeMethod(promise, fn,args);

            this.Tasks.Enqueue(taskBody);

            return promise;
        }

        private TaskBody _invokeMethod(object promise, string fn, params object[] args)
        {
            bool isExportedFunction = fn.IndexOf('?') > -1;
            string fnPath = fn;
            string method = string.Empty;

            if (isExportedFunction)
            {
                var fns = fn.Split('?');
                fnPath = fns[0];
                method = fns[1];
            }


            object parameter = string.Empty;
            if (isExportedFunction)
            {
                parameter = new
                {
                    IsUseState = false,
                    Parameters = args,
                    ExportedFunctionName = method,
                };
            }
            else
            {
                parameter = new
                {
                    Parameters = args
                };
            }

            string token = this.BuildTaskToken();

            var taskBody = new TaskBody
            {
                Token = token,
                Promise = promise,
                Body = new
                {
                    CommandText = "iTool Cloud Run " + fn,
                    Handel = "Command",
                    Parameter = parameter.TryToJson(),
                    Token = token
                }
            };

            return taskBody;
        }


        public Task<string> invokeMethodAsync(string fn, string key, params object[] args)
        {
            TaskCompletionSource<string> completionSource = new TaskCompletionSource<string>();
            var taskBody = this._invokeMethod(completionSource, fn, key, args);
            this.Tasks.Enqueue(taskBody);
            return completionSource.Task;
        }
        public Promise invokeMethod(string fn, string key, params object[] args)
        {
            var promise = new Promise();
            var taskBody = this._invokeMethod(promise, fn, key, args);
            this.Tasks.Enqueue(taskBody);
            return promise;
        }
        private TaskBody _invokeMethod(object promise, string fn, string key, params object[] args)
        {
            bool isExportedFunction = fn.IndexOf('?') > -1;
            string fnPath = fn;
            string method = string.Empty;

            if (isExportedFunction)
            {
                var fns = fn.Split('?');
                fnPath = fns[0];
                method = fns[1];
            }
            else
            {
                throw new Exception("fn 格式不正确， 例： folder/fileName?methodName");
            }

            object parameter = parameter = new
            {
                IsUseState = true,
                Parameters = args,
                ExportedFunctionName = method,
                StateKey = key
            };

            string token = this.BuildTaskToken();

            return new TaskBody
            {
                Token = token,
                Promise = promise,
                Body = new
                {
                    CommandText = "iTool Cloud Run " + fn,
                    Handel = "Command",
                    Parameter = parameter.TryToJson(),
                    Token = token
                }
            };
        }



        // Api Json
        public Task<string> invokeApiJsonAsync(string tableName, object commandScript, ApiJsonType type = ApiJsonType.Get)
        {
            TaskCompletionSource<string> completionSource = new TaskCompletionSource<string>();
            var taskBody = this._invokeApiJson(completionSource, tableName, commandScript, type);
            this.Tasks.Enqueue(taskBody);
            return completionSource.Task;
        }

        public Promise invokeApiJson(string tableName, object commandScript, ApiJsonType type = ApiJsonType.Get)
        {
            var promise = new Promise();
            var taskBody = this._invokeApiJson(promise, tableName, commandScript, type);
            this.Tasks.Enqueue(taskBody);
            return promise;
        }

        private TaskBody _invokeApiJson(object promise, string tableName, object commandScript, ApiJsonType type = ApiJsonType.Get)
        {

            object parameter = new
            {
                Script = commandScript.GetType() == typeof(string) ? (string)commandScript : commandScript.TryToJson(),
                MothodType = type.ToString(),
                Connaction = new
                {
                    Title = tableName
                }
            };

            string token = this.BuildTaskToken();

            var result = new TaskBody
            {
                Token = token,
                Promise = promise,
                Body = new
                {
                    CommandText = "iTool APIJSON",
                    Handel = "Command",
                    Parameter = parameter.TryToJson(),
                    Token = token
                }
            };
            Console.WriteLine(result.TryToJson());
            return result;
        }





        // 订阅
        public Task<string> SubscribeAsync(string topic)
        {
            TaskCompletionSource<string> completionSource = new TaskCompletionSource<string>();
            var taskBody = this._Subscribe(completionSource, topic);
            this.Tasks.Enqueue(taskBody);
            return completionSource.Task;
        }
        public Promise Subscribe(string topic)
        {
            var promise = new Promise();
            var taskBody = this._Subscribe(promise,topic);
            this.Tasks.Enqueue(taskBody);
            return (Promise)taskBody.Promise;
        }
        private TaskBody _Subscribe(object promise, string topic)
        {
            string token = this.BuildTaskToken();

            return new TaskBody
            {
                Token = token,
                Promise = promise,
                Body = new
                {
                    CommandText = "iTool Subscribe Channel",
                    Handel = "Command",
                    Parameter = topic,
                    Token = token
                }
            };
        }

        public Task<string> UnSubscribeAsync(string topic)
        {
            TaskCompletionSource<string> completionSource = new TaskCompletionSource<string>();
            var taskBody = this._UnSubscribe(completionSource, topic);
            this.Tasks.Enqueue(taskBody);
            return completionSource.Task;
        }

        public Promise UnSubscribe(string topic)
        {
            var promise = new Promise();
            var taskBody = this._UnSubscribe(promise,topic);
            this.Tasks.Enqueue(taskBody);
            return (Promise)taskBody.Promise;
        }

        private TaskBody _UnSubscribe(object promise, string topic)
        {
            string token = this.BuildTaskToken();

            return new TaskBody
            {
                Token = token,
                Promise = promise,
                Body = new
                {
                    CommandText = "iTool UnSubscribe Channel",
                    Handel = "Command",
                    Parameter = topic,
                    Token = token
                }
            };
        }





        // 消息部分

        public Task<string> NotifyAsync(string toChannel, string message, bool isMustBeServed = true)
        {
            TaskCompletionSource<string> completionSource = new TaskCompletionSource<string>();
            var taskBody = this.GetMessageOfNotify(completionSource, toChannel, message, isMustBeServed, true);
            this.Tasks.Enqueue(taskBody);
            return completionSource.Task;
        }
        public Promise Notify(string toChannel, string message, bool isMustBeServed = true)
        {
            var promise = new Promise();
            var taskBody = this.GetMessageOfNotify(promise, toChannel, message, isMustBeServed, true);
            this.Tasks.Enqueue(taskBody);
            return promise;
        }

        public Task<string> NotifyGroupAsync(string toChannel, string message, bool isMustBeServed = true)
        {
            TaskCompletionSource<string> completionSource = new TaskCompletionSource<string>();
            var taskBody = this.GetMessageOfNotify(completionSource, toChannel, message, isMustBeServed, true);
            this.Tasks.Enqueue(taskBody);
            return completionSource.Task;
        }
        public Promise NotifyGroup(string toChannel, string message, bool isMustBeServed = true)
        {
            var promise = new Promise();
            var taskBody = this.GetMessageOfNotify(promise,toChannel, message, isMustBeServed, true);
            this.Tasks.Enqueue(taskBody);
            return promise;
        }

        private TaskBody GetMessageOfNotify(object promise, string toChannel, string message, bool isMustBeServed, bool isGroup) 
        {
            string token = this.BuildTaskToken();

            return new TaskBody
            {
                Token = token,
                Promise = promise,
                Body = new
                {
                    ToChannel = toChannel,
                    Handel = "Notify",
                    Parameter = message,
                    IsGroup = isGroup,
                    IsMustBeServed = isMustBeServed,
                    Token = token
                }
            };
        }


        public Task<string> GetSessionAsync()
        {
            TaskCompletionSource<string> completionSource = new TaskCompletionSource<string>();
            string token = this.BuildTaskToken();

            var taskBody = new TaskBody
            {
                Token = token,
                Promise = completionSource,
                Body = new
                {
                    CommandText = "iTool Get Sesstion",
                    Handel = "Command",
                    Token = token
                }
            };

            this.Tasks.Enqueue(taskBody);

            return completionSource.Task;
        }

        public Promise GetSession()
        {
            string token = this.BuildTaskToken();

            var taskBody = new TaskBody
            {
                Token = token,
                Promise = new Promise(),
                Body = new
                {
                    CommandText = "iTool Get Sesstion",
                    Handel = "Command",
                    Token = token
                }
            };

            this.Tasks.Enqueue(taskBody);

            return (Promise)taskBody.Promise;
        }


        public Task<string> IntoChannelAsync(string channel)
        {
            TaskCompletionSource<string> completionSource = new TaskCompletionSource<string>();
            string token = this.BuildTaskToken();

            var taskBody = new TaskBody
            {
                Token = token,
                Promise = completionSource,
                Body = new
                {
                    CommandText = "iTool Sesstion IntoChannel",
                    Handel = "Command",
                    Parameter = channel,
                    Token = token
                }
            };

            this.Tasks.Enqueue(taskBody);

            return completionSource.Task;
        }

        public Promise IntoChannel(string channel)
        {
            string token = this.BuildTaskToken();

            var taskBody = new TaskBody
            {
                Token = token,
                Promise = new Promise(),
                Body = new
                {
                    CommandText = "iTool Sesstion IntoChannel",
                    Handel = "Command",
                    Parameter = channel,
                    Token = token
                }
            };

            this.Tasks.Enqueue(taskBody);

            return (Promise)taskBody.Promise;
        }

        public Task<string> OutChannelAsync(string channel)
        {
            TaskCompletionSource<string> completionSource = new TaskCompletionSource<string>();
            string token = this.BuildTaskToken();

            var taskBody = new TaskBody
            {
                Token = token,
                Promise = completionSource,
                Body = new
                {
                    CommandText = "iTool Sesstion OutChannel",
                    Handel = "Command",
                    Parameter = channel,
                    Token = token
                }
            };

            this.Tasks.Enqueue(taskBody);

            return completionSource.Task;
        }
        public Promise OutChannel(string channel)
        {
            string token = this.BuildTaskToken();

            var taskBody = new TaskBody
            {
                Token = token,
                Promise = new Promise(),
                Body = new
                {
                    CommandText = "iTool Sesstion OutChannel",
                    Handel = "Command",
                    Parameter = channel,
                    Token = token
                }
            };

            this.Tasks.Enqueue(taskBody);

            return (Promise)taskBody.Promise;
        }

        public Task<string> ReaderSessionByChannelAsync(string channel)
        {
            TaskCompletionSource<string> completionSource = new TaskCompletionSource<string>();
            string token = this.BuildTaskToken();

            var taskBody = new TaskBody
            {
                Token = token,
                Promise = completionSource,
                Body = new
                {
                    CommandText = "iTool Sesstion Reader",
                    Handel = "Command",
                    Parameter = channel,
                    Token = token
                }
            };

            this.Tasks.Enqueue(taskBody);

            return completionSource.Task;
        }
        public Promise ReaderSessionByChannel(string channel)
        {
            string token = this.BuildTaskToken();

            var taskBody = new TaskBody
            {
                Token = token,
                Promise = new Promise(),
                Body = new
                {
                    CommandText = "iTool Sesstion Reader",
                    Handel = "Command",
                    Parameter = channel,
                    Token = token
                }
            };

            this.Tasks.Enqueue(taskBody);

            return (Promise)taskBody.Promise;
        }

        public Task<string> RemoveSessionByChannelAsync(string channel)
        {
            TaskCompletionSource<string> completionSource = new TaskCompletionSource<string>();
            string token = this.BuildTaskToken();

            var taskBody = new TaskBody
            {
                Token = token,
                Promise = completionSource,
                Body = new
                {
                    CommandText = "iTool Sesstion RemoveSesstionByChannel",
                    Handel = "Command",
                    Parameter = channel,
                    Token = token
                }
            };

            this.Tasks.Enqueue(taskBody);

            return completionSource.Task;
        }
        public Promise RemoveSessionByChannel(string channel)
        {
            string token = this.BuildTaskToken();

            var taskBody = new TaskBody
            {
                Token = token,
                Promise = new Promise(),
                Body = new
                {
                    CommandText = "iTool Sesstion RemoveSesstionByChannel",
                    Handel = "Command",
                    Parameter = channel,
                    Token = token
                }
            };

            this.Tasks.Enqueue(taskBody);

            return (Promise)taskBody.Promise;
        }

        public Task<string> ModifyMessageStatusAsync(int id, int status)
        {
            TaskCompletionSource<string> completionSource = new TaskCompletionSource<string>();
            string token = this.BuildTaskToken();

            var taskBody = new TaskBody
            {
                Token = token,
                Promise = completionSource,
                Body = new
                {
                    CommandText = "iTool Modify MessageStatus",
                    Handel = "Command",
                    Parameter = new
                    {
                        id,
                        status
                    }.TryToJson(),
                    Token = token
                }
            };

            this.Tasks.Enqueue(taskBody);

            return completionSource.Task;
        }
        public Promise ModifyMessageStatus(int id, int status)
        {
            string token = this.BuildTaskToken();

            var taskBody = new TaskBody
            {
                Token = token,
                Promise = new Promise(),
                Body = new
                {
                    CommandText = "iTool Modify MessageStatus",
                    Handel = "Command",
                    Parameter = new {
                        id,
                        status
                    }.TryToJson(),
                    Token = token
                }
            };

            this.Tasks.Enqueue(taskBody);

            return (Promise)taskBody.Promise;
        }



        public Task<string> GetMessageAsync(string reciveChannel, Pagination pagination, DateTime? minDateTime, DateTime? minHistoryDateTime)
        {
            TaskCompletionSource<string> completionSource = new TaskCompletionSource<string>();
            string token = this.BuildTaskToken();

            var taskBody = new TaskBody
            {
                Token = token,
                Promise = completionSource,
                Body = new
                {
                    CommandText = "iTool Get Message",
                    Handel = "Command",
                    Parameter = new
                    {
                        reciveChannel,
                        pagination,
                        minDateTime,
                        minHistoryDateTime
                    }.TryToJson(),
                    Token = token
                }
            };

            this.Tasks.Enqueue(taskBody);

            return completionSource.Task;
        }
        public Promise GetMessage(string reciveChannel, Pagination pagination, DateTime? minDateTime, DateTime? minHistoryDateTime)
        {
            string token = this.BuildTaskToken();

            var taskBody = new TaskBody
            {
                Token = token,
                Promise = new Promise(),
                Body = new
                {
                    CommandText = "iTool Get Message",
                    Handel = "Command",
                    Parameter = new
                    {
                        reciveChannel,
                        pagination,
                        minDateTime,
                        minHistoryDateTime
                    }.TryToJson(),
                    Token = token
                }
            };

            this.Tasks.Enqueue(taskBody);

            return (Promise)taskBody.Promise;
        }

    }
}
